import random
import numpy as np
import logging
from detecter import settings

logger = logging.getLogger('django')
# 设置随机种子
random.seed(2020)
fpRand = [random.randint(-10, 10) for i in range(settings.E2HASH_K)]


A_GROUP = [[random.gauss(0, 1) for _ in range(settings.E2HASH_MAX_N)] for _ in range(settings.E2HASH_K)]
B_GROUP = [random.uniform(0, 1) for _ in range(settings.E2HASH_K)]

def genPara(n, r):
    """
    :param n: length of data vector
    :param r:
    :return: a, b
    """

    a = []
    for i in range(n):
        a.append(random.gauss(0, 1))
    b = random.uniform(0, r)

    return a, b


def gen_e2LSH_family(n, k, r):
    """
    :param n: length of data vector
    :param k:
    :param r:
    :return: a list of parameters (a, b)
    """
    result = []
    for i in range(k):
        result.append(genPara(n, r))

    return result


def gen_HashVals(e2LSH_family, v, r):
    """
    :param e2LSH_family: include k hash funcs(parameters)
    :param v: data vector
    :param r:
    :return hash values: a list
    """

    # hashVals include k values
    hashVals = []

    for hab in e2LSH_family:
        hashVal = (np.inner(hab[0], v) + hab[1]) // r
        hashVals.append(hashVal)

    return hashVals


def H2(hashVals, fpRand, k, C):
    """
    :param hashVals: k hash vals
    :param fpRand: ri', the random vals that used to generate fingerprint
    :param k, C: parameter
    :return: the fingerprint of (x1, x2, ..., xk), a int value
    """
    return int(sum([(hashVals[i] * fpRand[i]) for i in range(k)]) % C)


def e2LSH(dataSet, k, r, tableSize):
    """
    generate hash table
    * hash table: a list, [node1, node2, ... node_{tableSize - 1}]
    ** node: node.val = index; node.buckets = {}
    *** node.buckets: a dictionary, {fp:[v1, ..], ...}
    :param dataSet: a set of vector(list)
    :param k: each group contain k hash group
    :param r: 0-r random
    :param tableSize:
    :return: 3 elements, hash table, hash functions, fpRand
    """
    dataSet_new = {}
    hashTable = [[] for i in range(tableSize)]

    # 计算多少个样本
    n = len(dataSet[list(dataSet.keys())[0]])
    logger.info(n)

    C = pow(2, 32) - 5

    e2LSH_family = [[a[:n], b] for (a, b) in zip(A_GROUP, B_GROUP)]
    for dataIndex in dataSet.keys():
        # generate k hash values
        hashVals = gen_HashVals(e2LSH_family, dataSet[dataIndex], r)

        # generate fingerprint
        fp = H2(hashVals, fpRand, k, C)

        # generate index
        index = fp % tableSize

        hashTable[index].append(dataIndex)
        dataSet_new.update({dataIndex: (dataSet[dataIndex], index)})
    logger.info(hashTable)
    return dataSet_new, hashTable
